#include "ndata.h"
#include "..\dvb\dvb.h"
#include <string.h>
#include <stdlib.h>

DWORD Ndata::M_count = 0;

void Ndata::SetNull(void)
{
	NTYPE(m_bBuffer) = NULL_TYPE;
	m_len = NLENGTH(m_bBuffer) = 4;
}

void Ndata::SetDataBody(WORD type, const void* body, DWORD bodySize)
{
	_EnsureSize(4 + bodySize, 8);
	NTYPE(m_bBuffer) = type;
	memcpy_s(m_bBuffer + 4, bodySize, body, bodySize);
	m_len = NLENGTH(m_bBuffer) = (WORD)(4 + bodySize);
}

void Ndata::SetWord(WORD w)
{
	SetDataBody(W_TYPE, &w, sizeof(WORD));
}

void Ndata::SetDword(DWORD dw)
{
	SetDataBody(DW_TYPE, &dw, sizeof(DWORD));
}

void Ndata::SetDvb(DVB dvb)
{
	SetDataBody(DVB_TYPE, &dvb, sizeof(DVB));
}

WORD Ndata::DataType(void)
{
	return(NTYPE(m_bBuffer));
}

WORD Ndata::DataSize(void)
{
	return(NLENGTH(m_bBuffer) - 4);
}

const void* Ndata::DataBody(void)
{
	return(m_bBuffer + 4);
}

static WORD GetTypeWord(WORD type, const BYTE dataBody[])
{
	WORD w = 0;
	char firstChar;
	switch (type) {
	case W_TYPE:
	case DVB_TYPE:
	case DW_TYPE:
		w = *(WORD*)dataBody;
		break;
	case STR_TYPE:
		firstChar = dataBody[0];
		if ((firstChar >= '0' && firstChar <= '9') || firstChar == '-') {
			w = (WORD)atol((const char*)dataBody);
		}
		break;
	default:
		break;
	}
	return(w);
}

DWORD GetTypeDword(WORD type, const BYTE dataBody[])
{
	DWORD dw = 0;
	char firstChar;
	switch (type) {
	case W_TYPE:
		dw = *(WORD*)dataBody;
		break;
	case DVB_TYPE:
	case DW_TYPE:
		dw = *(DWORD*)(dataBody);
		break;
	case STR_TYPE:
		firstChar = dataBody[0];
		if ((firstChar >= '0' && firstChar <= '9') || firstChar == '-') {
			dw = (DWORD)atol((const char*)dataBody);
		}
		break;
	default:
		break;
	}
	return(dw);
}

long GetTypeInt(WORD type, const BYTE dataBody[])
{
	long iv = 0;
	char firstChar;
	switch (type) {
	case W_TYPE:
		iv = *(WORD*)dataBody;
		break;
	case DVB_TYPE:
		iv = Dvb2Int((*(DVB*)dataBody));
		break;
	case DW_TYPE:
		iv = *(DWORD*)(dataBody);
		break;
	case STR_TYPE:
		firstChar = dataBody[0];
		if ((firstChar >= '0' && firstChar <= '9') || firstChar == '-') {
			iv = atol((const char*)dataBody);
		}
		break;
	default:
		break;
	}
	return(iv);
}

double GetTypeFloat(WORD type, const BYTE dataBody[])
{
	double fv = 0;
	char firstChar;
	switch (type) {
	case W_TYPE:
		fv = *(WORD*)dataBody;
		break;
	case DVB_TYPE:
		fv = Dvb2Float((*(DVB*)dataBody));
		break;
	case DW_TYPE:
		fv = *(DWORD*)(dataBody);
		break;
	case STR_TYPE:
		firstChar = dataBody[0];
		if ((firstChar >= '0' && firstChar <= '9') || firstChar == '-') {
			fv = atof((const char*)dataBody);
		}
		break;
	default:
		break;
	}
	return(fv);
}

const char* GetTypeString(WORD type, const BYTE dataBody[])
{
	const char* str = "";
	switch (type) {
	case STR_TYPE:
		str = (const char*)dataBody;
		break;
	default:
		break;
	}
	return(str);
}

const DVB* GetTypeDvbArray(WORD type, const BYTE dataBody[])
{
	static const DVB EMPTY_DVBA[] = { EODVB };
	const DVB* dva = EMPTY_DVBA;
	switch (type) {
	case DVBA_TYPE:
		dva = (const DVB*)dataBody;
		break;
	default:
		break;
	}
	return(dva);
}

WORD Ndata::GetWord(void)
{
	return(GetTypeWord(NTYPE(m_bBuffer), m_bBuffer + 4));
}

DWORD Ndata::GetDword(void)
{
	return(GetTypeDword(NTYPE(m_bBuffer), m_bBuffer + 4));
}

long Ndata::GetInt(void)
{
	return(GetTypeInt(NTYPE(m_bBuffer), m_bBuffer + 4));
}

double Ndata::GetFloat(void)
{
	return(GetTypeFloat(NTYPE(m_bBuffer), m_bBuffer + 4));
}

const char* Ndata::GetString(void)
{
	return(GetTypeString(NTYPE(m_bBuffer), m_bBuffer + 4));
}

const DVB* Ndata::GetDvbArray(void)
{
	return(GetTypeDvbArray(NTYPE(m_bBuffer), m_bBuffer + 4));
}

void NCollection::AppendWord(WORD w)
{
	AppendDataBody(W_TYPE, &w, sizeof(WORD));
}

void NCollection::AppendDword(DWORD dw)
{
	AppendDataBody(DW_TYPE, &dw, sizeof(DWORD));
}

void NCollection::AppendDvb(DVB dvb)
{
	AppendDataBody(DVB_TYPE, &dvb, sizeof(DVB));
}

void NCollection::AppendMember(Ndata* paMember)
{
	AppendDataBody(paMember->DataType(), paMember->DataBody(), paMember->DataSize());
}

NList::NList(void) : NCollection(32)
{
	NTYPE(m_bBuffer) = LIST_TYPE;
	m_len = NLENGTH(m_bBuffer) = 4;
}

NList::NList(DWORD initSize) : NCollection(initSize)
{
	NTYPE(m_bBuffer) = LIST_TYPE;
	m_len = NLENGTH(m_bBuffer) = 4;
}

void NList::Reset(void)
{
	NTYPE(m_bBuffer) = LIST_TYPE;
	m_len = NLENGTH(m_bBuffer) = 4;
}

void NList::AppendDataBody(WORD type, const void* body, DWORD bodySize)
{
	if (m_len == 4) {
		_EnsureSize(8 + bodySize);
		BYTE* firstMemberPtr = m_bBuffer + 4;
		NTYPE(firstMemberPtr) = type;
		NLENGTH(firstMemberPtr) = (WORD)(4 + bodySize);
		memcpy_s(firstMemberPtr + 4, bodySize, body, bodySize);
		m_len = NLENGTH(m_bBuffer) = (WORD)(8 + bodySize);
	}
	else {
		BYTE* firstMemberPtr = m_bBuffer + 4;
		WORD memberType = NTYPE(firstMemberPtr);
		WORD memberDataSize = NLENGTH(firstMemberPtr) - 4;
		if (type == memberType && bodySize == memberDataSize) {
			_EnsureSize(m_len + bodySize);
			memcpy_s(m_bBuffer + m_len, m_size - m_len, body, bodySize);
			m_len = NLENGTH(m_bBuffer) = (WORD)(m_len + bodySize);
		}
	}
}

WORD NList::Count(void)
{
	WORD totalLength = NLENGTH(m_bBuffer);
	if (totalLength == 4) {
		return(0);
	}

	WORD memberLength = NLENGTH(m_bBuffer + 4);
	WORD memberDataSize = memberLength - 4;
	return((totalLength - 8) / memberDataSize);
}

BOOL NList::GetMember(Ndata* paDstMember, WORD index)
{
	WORD totalLength = NLENGTH(m_bBuffer);
	if (totalLength == 4) {
		return(FALSE);
	}

	WORD memberLength = NLENGTH(m_bBuffer + 4);
	WORD memberDataSize = memberLength - 4;
	WORD getPosi = 8 + memberDataSize * index;
	if (getPosi < totalLength) {
		paDstMember->SetDataBody(NTYPE(m_bBuffer + 4), m_bBuffer + getPosi, memberDataSize);
		return(TRUE);
	}
	else {
		return(FALSE);
	}
}

NPack::NPack(void) : NCollection(16)
{
	NTYPE(m_bBuffer) = PACK_TYPE;
	 m_len = NLENGTH(m_bBuffer) = 4;
}

NPack::NPack(DWORD initSize) : NCollection(initSize)
{
	NTYPE(m_bBuffer) = PACK_TYPE;
	m_len = NLENGTH(m_bBuffer) = 4;
}

void NPack::Reset(void)
{
	NTYPE(m_bBuffer) = PACK_TYPE;
	m_len = NLENGTH(m_bBuffer) = 4;
}

void NPack::AppendDataBody(WORD type, const void* body, DWORD bodySize)
{
	WORD appendLength = 4 + (WORD)bodySize;
	_EnsureSize(m_len + appendLength);

	BYTE* nextMemberPtr = m_bBuffer + m_len;
	NTYPE(nextMemberPtr) = type;
	NLENGTH(nextMemberPtr) = appendLength;
	memcpy_s(nextMemberPtr + 4, bodySize, body, bodySize);
	m_len = NLENGTH(m_bBuffer) = (WORD)(m_len + appendLength);
}

WORD NPack::Count(void)
{
	WORD totalLength = NLENGTH(m_bBuffer);
	WORD sumLength = 4;
	BYTE* memberPtr = m_bBuffer + 4;
	WORD count = 0;
	while (sumLength < totalLength) {
		WORD memberLength = NLENGTH(memberPtr);
		sumLength += memberLength;
		memberPtr += memberLength;
		count++;
	}
	return(count);
}

const BYTE* NPack::_GetMemberPtr(WORD index)
{
	WORD totalLength = NLENGTH(m_bBuffer);
	WORD sumLength = 4;
	BYTE* memberPtr = m_bBuffer + 4;
	WORD i = 0;
	while (i < index && sumLength < totalLength) {
		i++;
		WORD nextMemberLength = NLENGTH(memberPtr);
		sumLength += nextMemberLength;
		memberPtr += nextMemberLength;
	}
	return(i == index ? m_bBuffer + sumLength : NULL);
}

BOOL NPack::GetMember(Ndata* paDstMember, WORD index)
{
	const BYTE* memberPtr = _GetMemberPtr(index);
	if (memberPtr != NULL) {
		paDstMember->ImportN(memberPtr);
		return(TRUE);
	}
	else {
		return(FALSE);
	}
}

WORD NPack::GetMemberWord(WORD index)
{
	const BYTE* memberPtr = _GetMemberPtr(index);
	if (memberPtr != NULL) {
		return(GetTypeWord(NTYPE(memberPtr), memberPtr + 4));
	}
	else {
		return(0);
	}
}

DWORD NPack::GetMemberDword(WORD index)
{
	const BYTE* memberPtr = _GetMemberPtr(index);
	if (memberPtr != NULL) {
		return(GetTypeDword(NTYPE(memberPtr), memberPtr + 4));
	}
	else {
		return(0);
	}
}

long NPack::GetMemberInt(WORD index)
{
	const BYTE* memberPtr = _GetMemberPtr(index);
	if (memberPtr != NULL) {
		return(GetTypeInt(NTYPE(memberPtr), memberPtr + 4));
	}
	else {
		return(0);
	}
}

double NPack::GetMemberFloat(WORD index)
{
	const BYTE* memberPtr = _GetMemberPtr(index);
	if (memberPtr != NULL) {
		return(GetTypeFloat(NTYPE(memberPtr), memberPtr + 4));
	}
	else {
		return(0.0);
	}
}

const char* NPack::GetMemberString(WORD index)
{
	const BYTE* memberPtr = _GetMemberPtr(index);
	if (memberPtr != NULL) {
		return(GetTypeString(NTYPE(memberPtr), memberPtr + 4));
	}
	else {
		return(0);
	}
}

const DVB* NPack::GetMemberDvbArray(WORD index)
{
	const BYTE* memberPtr = _GetMemberPtr(index);
	if (memberPtr != NULL) {
		return(GetTypeDvbArray(NTYPE(memberPtr), memberPtr + 4));
	}
	else {
		return(0);
	}
}

WORD NPack::GetWord(void)
{
	return(GetTypeWord(NTYPE(m_bBuffer + 4), m_bBuffer + 8));
}
DWORD NPack::GetDword(void)
{
	return(GetTypeDword(NTYPE(m_bBuffer + 4), m_bBuffer + 8));
}

long NPack::GetInt(void)
{
	return(GetTypeInt(NTYPE(m_bBuffer + 4), m_bBuffer + 8));
}

double NPack::GetFloat(void)
{
	return(GetTypeFloat(NTYPE(m_bBuffer + 4), m_bBuffer + 8));
}

const char* NPack::GetString(void)
{
	return(GetTypeString(NTYPE(m_bBuffer + 4), m_bBuffer + 8));
}

const DVB* NPack::GetDvbArray(void)
{
	return(GetTypeDvbArray(NTYPE(m_bBuffer + 4), m_bBuffer + 8));
}
